/********************************************************************************
 * Copyright (c)2016-2020, ShenZhen WanJiaAn Technology CO.,LTD.
 * All Rights Reserved.
 *
 * File Name     : Net.c
 * Author        : joki.zhu
 * Date          : 2019-10-24
 *
 * Record        :
 * 1.Date        : 2019-10-24
 *   Author      : joki.zhu
 *   Modification: Created file
 ********************************************************************************/
#include "Net.h"
#include "app_common.h"
#include "pox_net.h"

#ifdef __HuaweiLite__
#include "netif/ifaddrs.h"
#include "lwip/sockets.h"
#include "lwip/api.h"
#include "lwip/sys.h"
#include "lwip/igmp.h"
#include "lwip/inet.h"
#include "lwip/tcp.h"
#include "lwip/raw.h"
#include "lwip/udp.h"
#include "lwip/tcpip.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/ip_addr.h"
#include "lwip/dhcp.h"
#include "lwip/filter.h"
#endif /* __HuaweiLite__ */

static struct hostent *gethostnameinfo (const char *host)
{
    static struct hostent hostbuf;
    struct hostent *hp;
    size_t hstbuflen;
    char tmphstbuf[1024];
    int res;
    int herr;

    hstbuflen = 1024;

    res = gethostbyname_r (host, &hostbuf, tmphstbuf, hstbuflen,
            &hp, &herr);
    /*  Check for errors.  */
    if (res || hp == NULL)
        return NULL;
    return hp;
}

int netliteos_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
{
   return lwip_getaddrinfo(node, service, hints, res);
}

void netlieos_freeaddrinfo(struct addrinfo *res)
{
    lwip_freeaddrinfo(res); 
}

struct hostent *netliteos_gethostbyname(const char *name)
{
    return lwip_gethostbyname(name);
}


static int domain_to_ip(char *inAddr, char *outIp)
{
    struct addrinfo * res;
    struct addrinfo hints;
    int succ = 0;
    struct sockaddr_in dst_addr;

    /* Judge whether the input address is domain name or IP */
    memset(&dst_addr, 0, sizeof(dst_addr));
    if ((dst_addr.sin_addr.s_addr = inet_addr(inAddr)) != INADDR_NONE)  {
        sprintf(outIp, "%s", inAddr);
        return 0;
    }
	
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET; /* Allow IPv4 */
    hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
    hints.ai_protocol = 0; /* Any protocol */
    hints.ai_socktype = SOCK_STREAM;
    succ = getaddrinfo(inAddr, NULL, &hints, &res);
    if (succ != 0) {
        // printf("can't get address info! error code = %d\n", succ);
        return -1;
	} else {
        if (res->ai_addr->sa_family == AF_INET)
        {
            if (outIp != NULL) {
                struct sockaddr_in* pServAddr = (struct sockaddr_in *)res->ai_addr;
                inet_ntop(AF_INET, &(pServAddr->sin_addr), outIp, INET_ADDRSTRLEN);
            }
        }
    }

    freeaddrinfo(res);

    return 0;
}

//liteos getaddrinfo
int NetLiteosGetAddrInfo(char *inAddr, char *outIp)
{
    if (inAddr == NULL || outIp == NULL) {
        return -1;
    }

    domain_to_ip(inAddr, outIp);
    
    return 0;
}

int NetIperf(int argc, char *argv[])
{
#if 0
    extern int iperf_main(int argc, char *argv[]);
	iperf_main(argc, argv);
#else
    extern int cmd_iperf(int argc, char *argv[]);
    cmd_iperf(argc, argv);
#endif
	return 0;
}

int NetSetDns(char *dns1, char *dns2)
{
    int argc = 0;
    char *argv[2] = {NULL, NULL};
    
    extern u32_t osShellDns(int argc, char **argv);

    if (dns1 != NULL) 
    {
        argv[0]= "1";
        argv[1] = dns1;
        argc = 2;
        osShellDns(argc, argv);
    }

    if (dns2 != NULL)
    {
        argv[0]= "2";
        argv[1] = dns2;
        argc = 2;
        osShellDns(argc, argv);       
    }
    
    return 0;
}

int NetGetDns(char *dns1, char *dns2)
{
    if (dns1 == NULL || dns2 == NULL) {
        LOGE("Params is invalid\n");
        return -1;
    }
    
    int i = 0;
    ip_addr_t dns;
    err_t err;
    char strdns[2][32] = {"", ""};
    
    for (i = 0; i < 2; i++)
    {
        err = lwip_dns_getserver((u8_t)i, &dns);
        if (err == ERR_OK) {
            snprintf(strdns[i], 16, "%s", ipaddr_ntoa(&dns));
        }
    }
    
    snprintf(dns1, 16, "%s", strdns[0]);
    snprintf(dns2, 16, "%s", strdns[1]);

    LOGD("dns1: %s dns2: %s\n", dns1, dns2);
    
    return 0;
}

int NetGetAttrInfo(char *ifname, NET_ATTR_INFO_S *pstNetAttrInfo)
{
    if (ifname == NULL || pstNetAttrInfo == NULL) {
        LOGE("Params is invalid\n");
        return -1;
    }
    
    int ret = 0;

#ifdef __HuaweiLite__
    ip_addr_t ip;
    ip_addr_t netmask;
    ip_addr_t gateway;
    struct netif *pstNetif = NULL;
    
    pstNetif = netif_find(ifname);
    if (pstNetif != NULL) {
        netifapi_netif_get_addr(pstNetif, &ip, &netmask, &gateway);
        snprintf(pstNetAttrInfo->ip, 16, "%s", ipaddr_ntoa(&ip));
        snprintf(pstNetAttrInfo->netmask, 16, "%s", ipaddr_ntoa(&netmask));
        snprintf(pstNetAttrInfo->gateway, 16, "%s", ipaddr_ntoa(&gateway));
    }
    
	ret = pox_get_macaddr(ifname, pstNetAttrInfo->mac);
	if (PoxNetRet_TRUE != ret){
		LOGE("pox_get_macaddr %s failed\n", ifname);
	}

	NetGetDns(pstNetAttrInfo->dns1, pstNetAttrInfo->dns2);
#else
	ret = pox_get_macaddr(ifname, pstNetAttrInfo->mac);
	if (PoxNetRet_TRUE != ret){
		LOGE("pox_get_macaddr %s failed\n", ifname);
	}

	ret = pox_get_ipaddr(ifname, (char*)pstNetAttrInfo->ip);
	if (PoxNetRet_TRUE != ret){
		LOGE("pox_get_ipaddr %s failed", ifname);
	}
#endif /* __HuaweiLite__ */

    return 0;
}

int NetSetAttrInfo(char *ifname, NET_ATTR_INFO_S stNetAttrInfo)
{
    if (ifname == NULL) {
        LOGE("Params is invalid\n");
        return -1;
    }

    int ret = 0;

#ifdef __HuaweiLite__
    ip_addr_t   st_gw;
    ip_addr_t   st_ipaddr;
    ip_addr_t   st_netmask;
    struct netif *pstNetif = NULL;

    pstNetif = netif_find(ifname);
    if (pstNetif != NULL) {
        ipaddr_aton(stNetAttrInfo.ip, &st_ipaddr);
        ipaddr_aton(stNetAttrInfo.netmask, &st_netmask);
        ipaddr_aton(stNetAttrInfo.gateway, &st_gw);
        
        netifapi_netif_set_addr(pstNetif, &st_ipaddr, &st_netmask, &st_gw);
    }
#else
    
#endif /* __HuaweiLite__ */

    return 0;
}

/**
 * 网络ping
 *
 * @param[in] hostname 主机名 域名/IP
 * @param[in] cout 发送ping包个数
 * @param[in] timeoutMs 每个ping包等待接收的超时毫秒数
 *
 * @retval 0 网络异常
 * @retval 1 网络正常
 *
 * @attention 无
 */
int NetPing(char *hostname, int count, int timeoutMs)
{
	return icmp_ping(hostname, count, timeoutMs);
}
